from flask import Flask, render_template, request, redirect, url_for,send_from_directory,send_file
from flask import session,jsonify
import pygame._sdl2 as sdl2
from pygame import mixer
import pygame.mixer
import keyboard
import threading
import datetime
import requests
import socket
import ollama
import random
import shutil
import wave
import json
import time
import os 
import re

app = Flask(__name__)

app.secret_key = ''

with open('config/配置文件/姓.txt','r',encoding = 'utf-8') as f:
    first_names = [word.strip() for word in f.readlines() if word.strip()]

with open('config/配置文件/男名.txt','r',encoding = 'utf-8') as f:
    male_last_names = [word.strip() for word in f.readlines() if word.strip()]

with open('config/配置文件/女名.txt','r',encoding = 'utf-8') as f:
    female_last_names = [word.strip() for word in f.readlines() if word.strip()]

with open('config/配置文件/过滤词.txt','r',encoding = 'utf-8') as f:
    filter_key_words = [word.strip() for word in f.readlines() if word.strip()]

with open('config/配置文件/敏感词.txt','r',encoding = 'utf-8') as f:
    sensitive_words = [word.strip() for word in f.readlines() if word.strip()]

with open('config/配置文件/数字.txt','r',encoding = 'utf-8') as f:
    replace_key_words = [word.strip().replace('|','|').split('：') for word in f.readlines() if word.strip()]

with open('config/配置文件/替换词.txt','r',encoding = 'utf-8') as f:
    replace_key_words += [word.strip().replace('|','|').split('：') for word in f.readlines() if word.strip()]

with open('config/配置文件/保留词.txt','r',encoding = 'utf-8') as f:
    keep_words = {word.strip():''.join(random.sample('abcdefghijklmnopqrstuvwxyz',5)) for word in f.readlines() if word.strip()}

with open('config/配置文件/报时.txt','r',encoding = 'utf-8') as f:
    baoshi_info = {word.strip().split('：')[0] : word.strip().split('：')[1] for word in f.readlines() if word.strip()}


female_names = [a + b + c for a in first_names for b in female_last_names for c in female_last_names]

male_names = [a + b + c for a in first_names for b in male_last_names for c in male_last_names]

yonghu_names = ['用户' + ''.join(random.sample(['一','二','三','四','五','六','七','八','九'],4)) for i in range(10000)]


# 扩展句子变量
def expand_sentence(s):
    global female_names,male_names,yonghu_names

    s = s.replace('|','|')
    
    n = random.uniform(0,1)

    # {昵称}
    for i in range(10):
        if n > 0.66:
            s = re.sub('{昵称}',random.choice(female_names) + random.choice(['宝宝','姐姐']),s, count = 1)
        elif n > 0.33:
            s = re.sub('{昵称}', random.choice(male_names) + random.choice(['宝宝','哥哥']),s, count = 1)
        else:
            s = re.sub('{昵称}', random.choice(yonghu_names) + random.choice(['宝宝']),s, count = 1)
    
    # {xxxx}
    for item in re.findall('\{.+?\}',s):
        if random.random() > 0.5:
            s = s.replace(item,item.strip('{}'),1)
        else:
            s = s.replace(item,'',1)
    
    # <A、B、C、D、E>随机排列组合
    for item in re.findall('<.+?>',s):
        data = item.strip('<>').split('、')
        random.shuffle(data)
        s = s.replace(item,'、'.join(data),1)
    
    # <A，B，C，D，E>随机排列组合
    for item in re.findall('<，+?>',s):
        data = item.strip('<>').split('，')
        random.shuffle(data)
        s = s.replace(item,'，'.join(data),1)
    
    # [A|B|C]随机抽取一个
    for match in re.findall("\[.+?\]", s):
        s = s.replace(match,random.choice(match.strip('[').strip(']').split('|')),1)
    
    # 【A|B|C】随机抽取一个
    for match in re.findall("【.+?】", s):
        s = s.replace(match,random.choice(match.strip('【').strip('】').split('|')),1)
    
    return s.strip()


reply_sents_map = {}

for file in os.listdir('config/配置文件/回复'):
    if not file.endswith('.txt'):
        continue

    reply_sents_map[file.replace('.txt','')] = {
        'lines': [],
        'map': {

        }
    }

    with open(os.path.join('config/配置文件/回复',file),'r',encoding = 'utf-8') as f:
        for line in f.readlines():
            expline = expand_sentence(line)
            reply_sents_map[file.replace('.txt','')]['lines'].append(expline)
            reply_sents_map[file.replace('.txt','')]['map'][expline] = line


# 产品列表
products = [product for product in os.listdir(os.path.join('config','话术脚本')) if os.path.isdir(os.path.join('config','话术脚本',product))]

# 音色列表
streamers = [streamer for streamer in os.listdir(os.path.join('D:\\','音色定制')) if os.path.isdir(os.path.join('D:\\','音色定制',streamer))]

task_config = {}

for scene in ['scene-1','scene-2','scene-3','scene-4','scene-5']:
    task_config[scene] = {
        'scene_name': scene,
        'current_model': '',
        'current_product': '',
        'current_streamer': '',
        'current_temperature': '',
        'startGenScript': False,
        'startGenAudio': False,
        'startPreReplyAudio':False,
        'tempScript': [],
        'histFiles':{},
        'histSents':{},
        'active': True if scene == 'scene-1' else False
    }


# 文件重复性分析
def file_repeaty_analy(content,k = 20):
    content = re.sub('、|，|。|！|？','',content)
    
    info = {}
    
    # 文本截取的长度    
    for idx in range(0,len(content) - k):
        s = content[idx : idx + k]
        
        if not s in info:
            info[s] = 0
        
        info[s] += 1
        
    for i in info:
        if info[i] > 1:
            print(i,'出现',info[i],'次')
            print_split_line()
            return True
    
    return False


# 请求qwen3生成话术脚本
def ollama_generate_local(prompt,scene_idx,origin_script):
    global task_config

    print('prompt：',prompt)
    print('model：',task_config[scene_idx]['current_model'])
    print('temperature：',task_config[scene_idx]['current_temperature'])

    print_split_line()
    
    options = {

    }

    if task_config[scene_idx]['current_temperature']:
        options['temperature'] = float(task_config[scene_idx]['current_temperature'])

    resp = ollama.generate(
        model = task_config[scene_idx]['current_model'],
        prompt = prompt,
        stream = False,
        options = options
    )
        

    resp['response'] = re.sub('（.+?）|【.+?】|\(.+?\)','',resp['response'],flags = re.DOTALL)
    resp['response'] = re.sub(r'<think>(.*?)</think>','',resp['response'],flags = re.DOTALL)
    resp['response'] = re.sub(r'</think>.*','',resp['response'],flags = re.DOTALL)
    resp['response'] = re.sub('\n\n','\n',resp['response'])
    resp['response'] = re.sub('\*|\-|#','',resp['response'])

    result = ''
    
    for line in resp['response'].split():
        line = line.strip()
        
        # 太短的句子需要过滤
        if len(line) < 30:
            continue

        if re.search('一、|二、|三、|四、|五、|六、|七、|八、|九、',line):
            continue

        repeated = False
        
        # 生成的文案内部的相似性检查
        for start in range(0,len(line) - 30):
            for end in range(start + 30,len(line)):
                if line[start:end] in result:
                    repeated = True


        # 句子内部重复性检查
        for start in range(0,len(line) - 5):
            for end in range(start + 5,len(line)):
                if line.count(line[start:end]) > 2:
                    repeated = True

        # 生成的文案和原文案的相似度检查
        for start in range(0,len(line) - 30):
            for end in range(start + 30,len(line)):
                if line[start:end] in origin_script:
                    repeated = True

        if not repeated:
            result += line.strip() + '\n'
    
    return result


# 打印分割线
def print_split_line():
    width = os.get_terminal_size().columns
    text = '=' * width
    print(text)


# 清洗话术
def clear_content(content):
    global keep_words,replace_key_words,filter_key_words,sensitive_words

    content = content.replace('<think>','')
    content = content.replace('</think>','')
    content = content.lower().strip()
    
    if not content:
        return

    # 保留词
    for k in keep_words:
        content = re.sub(k,keep_words[k],content)

    content = re.sub('“|”','',content)
    content = re.sub('地','的',content)

     # 遇到过滤词（涉及到不合逻辑词）和敏感词（涉及到广告法）就直接跳过这一整句
    if re.search('|'.join(filter_key_words + sensitive_words),content):
        return ''
    
    # 替换词
    for rep_word in replace_key_words:
        content = re.sub(rep_word[0],rep_word[1],content)

    # 还原保留词
    for k in keep_words:
        content = re.sub(keep_words[k],k,content)

    content = content.replace('杯子子','杯子')

    return content.strip()


# 解析音色克隆文件
def parse_ref_audio_text(scene_idx):
    global task_config

    wav_path_list = [file for file in os.listdir(os.path.join('D:\\','音色定制',task_config[scene_idx]['current_streamer'],'wavs')) if file.endswith('.wav') or file.endswith('.WAV')]

    wav_path_random = random.choice(wav_path_list)

    ref_wav = os.path.abspath(os.path.join('D:\\','音色定制',task_config[scene_idx]['current_streamer'],'wavs',wav_path_random))
    ref_txt = os.path.abspath(os.path.join('D:\\','音色定制',task_config[scene_idx]['current_streamer'],'txts',wav_path_random + '.txt'))

    with open(ref_txt,'r+',encoding = 'utf-8') as f:
        ref_txt = f.read().strip()

    return ref_wav,ref_txt


# 解析音色克隆文件
def parse_ref_audio_text_by_streamer(streamer):
    global task_config

    result = []

    wav_path_list = [file for file in os.listdir(os.path.join('D:\\','音色定制',streamer,'wavs')) if file.endswith('.wav') or file.endswith('.WAV')]

    for wav_path in wav_path_list:
        ref_wav = os.path.abspath(os.path.join('D:\\','音色定制',streamer,'wavs',wav_path))
        ref_txt = os.path.abspath(os.path.join('D:\\','音色定制',streamer,'txts',wav_path + '.txt'))

        with open(ref_txt,'r+',encoding = 'utf-8') as f:
            ref_txt = f.read().strip()

        result.append({
            'ref_wav':ref_wav,
            'ref_txt':ref_txt
        })

    return result


# 读取当前北京时间
def read_current_time():
    global baoshi_info

    formats = [
        "现在是北京时间%Y年%m月%d日%H点%M分，",
        "现在是%Y年%m月%d日%H点%M分，",
        "现在时间来到了%H点%M分，",
        "时间来到了%H点%M分，",
        "现在时间是%H点%M分，"
    ]

    tinfo = datetime.datetime.now().strftime(random.choice(formats))

    for k in baoshi_info:
        if k in tinfo:
            tinfo = tinfo.replace(k,baoshi_info[k])

    return tinfo


# 开始仿写话术
def startGenScriptTask(scene_idx):
    global task_config,used_files
    
    prompt_sents = []

    tongyong_sents = []

    # 话术正文
    with open(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'话术.txt'),'r+',encoding = 'utf-8') as f:
        prompt_sents += [line.strip() for line in f.readlines() if line.strip()]

    # prompt前缀
    with open(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'prefix.txt'),'r+',encoding = 'utf-8') as f:
        prefix = f.read().strip()

    # prompt后缀
    with open(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'suffix.txt'),'r+',encoding = 'utf-8') as f:
        suffix = f.read().strip()
    
    # 如果有通用话术就读取通用话术
    if os.path.exists(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'通用.txt')):
        file_name = open(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'通用.txt'),'r+',encoding = 'utf-8').read().strip()

        if file_name:
            tongyong_sents += [line.strip() for line in open(os.path.join('config','话术脚本','通用',file_name),'r+',encoding = 'utf-8').readlines() if line.strip()]

    for i in range(5000000):
        gpu_occupied = False

        # 如果其他场景正在生成脚本，则表示GPU繁忙
        for scene in task_config:
            if task_config[scene]['startGenScript']:
                print('startGenScriptTask:',scene,'正在生成文案')
                gpu_occupied = True

        # 如果其他场景正在生成声音，则表示GPU繁忙
        for scene in task_config:
            if task_config[scene]['startGenAudio']:
                print('startGenScriptTask:',scene,'正在生成音频')
                gpu_occupied = True

        if gpu_occupied:
            time.sleep(random.uniform(0,1))
            continue

        task_config[scene_idx]['startGenScript'] = True

        # 生成提示词
        # if len(prompt_sents) > 10:
        #     sents = random.sample(prompt_sents,10) + random.sample(tongyong_sents,10)
        # else:
        #     sents = random.sample(tongyong_sents,20)

        sents = random.sample(tongyong_sents + prompt_sents,20)
        
        random.shuffle(sents)

        p = ''.join(sents)

        prompt = prefix.replace('{商品名称}',task_config[scene_idx]['current_product']) + p + suffix.replace('{字数}',str(int(len(p) * 2)))
        
        # 调用qwen3生成话术
        result = ollama_generate_local(prompt,scene_idx,p)

        print('泛化结果：',result)
        
        print_split_line()

        if len(result) / len(p) > 0.5:
            path = os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx,'%s.txt' % datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")) 
    
            with open(path,'w',encoding = 'utf-8') as f:
                f.write(result)
        else:
            print('字数不足0.5倍')
            print_split_line()

        # 空出资源让其他任务开始执行
        task_config[scene_idx]['startGenScript'] = False

        # 这里睡眠一下为的是让其他任务有机会可以执行
        time.sleep(random.uniform(0,1))


# 开始生成主音频
def startGenMainAudioTask(scene_idx):
    global task_config

    # 互动话术
    with open(os.path.join('config','配置文件','互动.txt'),'r+',encoding = 'utf-8') as f:
        hudong_sents = [line.strip() for line in f.readlines() if line.strip()]

    for i in range(10000000):
        # 如果剩余库存达到100，则可以多休眠一下，因为GPU还时不时需要用来生成插话音频
        if len(os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx))) > 100:
            print(scene_idx,'剩余音频库存达到100，休眠60秒')
            time.sleep(60)
            continue

        gpu_occupied = False

        # 如果其他场景正在生成脚本，则表示GPU繁忙
        for scene in task_config:
            if task_config[scene]['startGenScript']:
                print('startGenMainAudioTask:',scene,'正在生成话术')
                gpu_occupied = True

        # 如果其他场景正在生成声音，则表示GPU繁忙
        for scene in task_config:
            if task_config[scene]['startGenAudio']:
                print('startGenMainAudioTask:',scene,'正在生成音频')
                gpu_occupied = True

        if gpu_occupied:
            time.sleep(random.uniform(0,1))
            continue

        files = [file for file in os.listdir(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx)) if file.endswith('.txt') and not file in task_config[scene_idx]['histFiles']]

        if files:
            path = os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx,files.pop(0))
        else:
            time.sleep(1)
            continue

        # 表示开始生成音频，要占用GPU
        task_config[scene_idx]['startGenAudio'] = True

        with open(path,'r+',encoding = 'utf-8') as f2:
            lines = f2.readlines()[1:-1]

            for line in lines:
                gen_text = clear_content(line)

                if not gen_text or gen_text in task_config[scene_idx]['histSents']:
                    continue

                # 此处不可省略，因为有时候会遇到文件删除不掉的情况，防止文件被重复使用。
                task_config[scene_idx]['histSents'][gen_text] = 1

                ref_wave,ref_text = parse_ref_audio_text(scene_idx)

                print(gen_text)
                print_split_line()

                response = requests.post('http://127.0.0.1:5000/generate_audio',data = {
                    'ref_file':ref_wave,
                    'ref_text':ref_text,
                    'gen_text':gen_text,
                    'speed': 1
                })
                
                # 检查请求是否成功
                if response.status_code == 200:
                    save_path = os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx,'%s.wav' % datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))

                    with open(save_path, 'wb') as f4:
                        f4.write(response.content)

                if random.uniform(0,1) > 0.3:
                    gen_text = expand_sentence(random.choice(hudong_sents))

                    print(gen_text)
                    print_split_line()

                    response = requests.post('http://127.0.0.1:5000/generate_audio',data = {
                        'ref_file':ref_wave,
                        'ref_text':ref_text,
                        'gen_text':gen_text,
                        'speed': 1
                    })
                    
                    # 检查请求是否成功
                    if response.status_code == 200:
                        save_path = os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx,'%s.wav' % datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))

                        with open(save_path, 'wb') as f4:
                            f4.write(response.content)

        # 空出资源让其他任务开始执行
        task_config[scene_idx]['startGenAudio'] = False

        # 这里睡眠一下为的是让其他任务有机会可以执行
        time.sleep(random.uniform(0,1))
            
        # 先尝试着删除文件，不管有没有删除掉都要标记此文件已经使用过，后面不能再使用
        try:
            os.remove(path)
        except:
            pass

        task_config[scene_idx]['histFiles'][file] = 1


# 开始生成临时音频
def startGenSubAudioTask(scene_idx):
    global task_config

    for i in range(8640000):
        ref_wave,ref_text = parse_ref_audio_text(scene_idx)

        while task_config[scene_idx]['tempScript']:
            gen_text = task_config[scene_idx]['tempScript'].pop(0).strip()

            streamer = task_config[scene_idx]['current_streamer']

            print(os.path.join('config','回复音频',streamer,gen_text),os.path.exists(os.path.join('config','回复音频',streamer,gen_text)))

            # 如果在缓存里有这个文件的话直接用这个缓存文件
            if os.path.exists(os.path.join('config','回复音频',streamer,gen_text)) and [wf for wf in os.listdir(os.path.join('config','回复音频',streamer,gen_text)) if wf.endswith('.wav')]:
                files_total = [wf for wf in os.listdir(os.path.join('config','回复音频',streamer,gen_text)) if wf.endswith('.wav')]
                file_random = random.choice(files_total)
                file_path = os.path.join(os.path.join('config','回复音频',streamer,gen_text,file_random))
                save_path = os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx,'%s.wav' % datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))
                shutil.copy(file_path,save_path)
                print(gen_text,'有缓存，已复制')

            else:
                print('正在生成临时音频：',gen_text)

                response = requests.post('http://127.0.0.1:5000/generate_audio',data = {
                    'ref_file':ref_wave,
                    'ref_text':ref_text,
                    'gen_text':gen_text,
                    'speed': 1
                })
                
                # 检查请求是否成功
                if response.status_code == 200:
                    save_path = os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx,'%s.wav' % datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))

                    with open(save_path, 'wb') as f4:
                        f4.write(response.content)

        time.sleep(0.1)

            
@app.route('/')
def login():
    return render_template('login.html')


@app.route('/index')
def index():
    mixer.init()
    devices = sdl2.audio.get_audio_device_names(False) + ['桌面音频']
    mixer.quit()

    temperatures = [str(round(i / 10,1)) for i in range(0,21)]
    
    models = [line.split()[0] for line in os.popen('ollama list').read().split('\n')[1:-1]]

    return render_template('index.html', products = products, streamers = streamers,devices = devices,temperatures = temperatures,models = models)


# 开始生成话术
@app.route('/startGenScript',methods = ['POST'])
def startGenScript():
    global task_config

    scene_idx = request.form.get('scene_idx')

    if not os.path.exists(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'])):
        os.mkdir(os.path.join('config','话术脚本',task_config[scene_idx]['current_product']))

    if not os.path.exists(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库')):
        os.mkdir(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库'))

    if not os.path.exists(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx)):
        os.mkdir(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx))
        
    # task_config[scene_idx]['startGenScriptTask'] =  True

    task_thread = threading.Thread(target = startGenScriptTask,args = (scene_idx,))
    task_thread.start()

    return jsonify({'success':True,'message':''})


# 暂停生成话术
# @app.route('/stopGenScript',methods = ['POST'])
# def stopGenScript():
#     global task_config

#     scene_idx = request.form.get('scene_idx')

#     task_config[scene_idx]['startGenScriptTask'] =  False

#     return jsonify({'success':True,'message':''})


# 开始生成音频
@app.route('/startGenAudio',methods = ['POST'])
def startGenAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    # task_config[scene_idx]['startGenAudioTask'] = True

    # 开始生成主音频
    task_thread = threading.Thread(target = startGenMainAudioTask,args = (scene_idx,))
    task_thread.start()

    # 开始生成临时音频
    task_thread = threading.Thread(target = startGenSubAudioTask,args = (scene_idx,))
    task_thread.start()

    return jsonify({'success':True,'message':''})


# 暂停生成音频
# @app.route('/stopGenAudio',methods = ['POST'])
# def stopGenAudio():
#     global task_config

#     scene_idx = request.form.get('scene_idx')

#     task_config[scene_idx]['startGenAudioTask'] = False

#     return jsonify({'success':True,'message':''})


# 清空话术
@app.route('/clearScript',methods = ['POST'])
def clearScript():
    global task_config

    scene_idx = request.form.get('scene_idx')

    # 先清空历史脚本
    for file in os.listdir(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx)):
        os.remove(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx,file))

    return jsonify({'success':True,'message':''})


# 清空音频
@app.route('/clearAudio',methods = ['POST'])
def clearAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['current_product'])):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product']))

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播')):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播'))

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时')):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时'))

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx)):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx))

    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx)):
        os.mkdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx))

    # 先清空历史音频
    for file in os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx)):
        os.remove(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx,file))

    for file in os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx)):
        os.remove(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx,file))

    return jsonify({'success':True,'message':''})


# 选择音色
@app.route('/selectStreamer',methods = ['POST'])
def selectStreamer():
    global task_config

    scene_idx = request.form.get('scene_idx')
    current_streamer = request.form.get('streamer')

    task_config[scene_idx]['current_streamer'] = current_streamer

    return jsonify({'success':True,'message':'已切换到' + current_streamer})


# 选择产品
@app.route('/selectProduct',methods = ['POST'])
def selectProduct():
    global task_config

    scene_idx = request.form.get('scene_idx')
    current_product = request.form.get('product')

    task_config[scene_idx]['current_product'] = current_product

    return jsonify({'success':True,'message':'已切换到' + current_product})


# 选择温度
@app.route('/selectTemperature',methods = ['POST'])
def selectTemperature():
    global task_config

    scene_idx = request.form.get('scene_idx')
    current_temperature = request.form.get('temperature')

    task_config[scene_idx]['current_temperature'] = current_temperature

    return jsonify({'success':True,'message':'已切换到' + current_temperature})


# 选择模型
@app.route('/selectModel',methods = ['POST'])
def selectModel():
    global task_config

    scene_idx = request.form.get('scene_idx')
    current_model = request.form.get('model')

    task_config[scene_idx]['current_model'] = current_model

    return jsonify({'success':True,'message':'已切换到' + current_model})


# 选择场景
@app.route('/selectScene',methods = ['POST'])
def selectScene():
    global task_config

    scene_idx = request.form.get('scene_idx')
    
    task_config[scene_idx]['active'] = True


    return jsonify({'success':True,'message':''})


# 同步配置信息
@app.route('/update_task_config',methods = ['POST'])
def update_task_config():
    global task_config

    return jsonify(task_config)


# 获取插话列表
@app.route('/getReplySents',methods = ['POST'])
def getReplySents():
    global task_config,reply_sents_map

    product = request.form.get('product')  

    if product in reply_sents_map:
        reply_sents =  reply_sents_map[product]['lines']
    else:
        reply_sents = []

    return jsonify({'success':True,'data':reply_sents})


# 发送插话
@app.route('/sendReplySent',methods = ['POST'])
def sendReplySent():
    global task_config,reply_sents_map

    scene_idx = request.form.get('scene_idx')
    product = request.form.get('product')
    content = request.form.get('content')

    print('插话：',product,content)

    if product in reply_sents_map and content in reply_sents_map[product]['map']:
        content  = expand_sentence(reply_sents_map[product]['map'][content])

    task_config[scene_idx]['tempScript'].append(re.sub('==.+==','',content))

    return jsonify({'success':True,'message':''})


# 查询音频库存
@app.route('/getAudioCount',methods = ['POST'])
def getAudioCount():
    global task_config,reply_sents_map

    scene_idx = request.form.get('scene_idx')

    if not task_config[scene_idx]['current_product']:
        return jsonify({'success':True,'count': -1})
    
    if not os.path.exists(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx)):
        return jsonify({'success':True,'count': -1})
    
    data = [file for file in os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx))]

    return jsonify({'success':True,'count':len(data)})



# 查询话术库存
@app.route('/getScriptCount',methods = ['POST'])
def getScriptCount():
    global task_config,reply_sents_map

    scene_idx = request.form.get('scene_idx')

    if not task_config[scene_idx]['current_product']:
        return jsonify({'success':True,'count': -1})

    if not os.path.exists(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx)):
        return jsonify({'success':True,'count': -1})

    data = [file for file in os.listdir(os.path.join('config','话术脚本',task_config[scene_idx]['current_product'],'文本库',scene_idx))]

    return jsonify({'success':True,'count':len(data)})



# 返回主音频【服务端接口】
main_audio_hist = []

def del_file(file_path):
    time.sleep(1)
    os.remove(file_path)


@app.route('/download_main_audio', methods = ['POST'])
def download_main_audio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    files = sorted([file for file in os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx)) if file.endswith('.wav') and not file in main_audio_hist])

    if not files:
        return '',404

    file_path = os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'主播',scene_idx,files[0])

    response =  send_file(file_path,as_attachment = True)

    main_audio_hist.append(files[0])

    task_thread = threading.Thread(target = del_file,args = (file_path,))
    task_thread.start()

    return response


# 返回辅音频【服务端接口】
sub_audio_hist = []

@app.route('/download_sub_audio', methods = ['POST'])
def download_sub_audio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    files = sorted([file for file in os.listdir(os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx)) if file.endswith('.wav') and not file in sub_audio_hist])

    if not files:
        return '',404

    file_path = os.path.join('config','话术音频',task_config[scene_idx]['current_product'],'临时',scene_idx,files[0])
    
    response = send_file(file_path,as_attachment = True)
    
    sub_audio_hist.append(files[0])

    task_thread = threading.Thread(target = del_file,args = (file_path,))
    task_thread.start()

    return response


# 预制回复音频
def startPreReplyAudioTask(scene_idx,product,streamer):
    global task_config

    fp = os.path.join('config/配置文件/回复',product + '.txt')

    with open(fp,'r',encoding = 'utf-8') as f:
        for line in f.readlines():
            if not line.strip():
                continue

            if not task_config[scene_idx]['startPreReplyAudio']:
                break
            
            line = re.sub('==.+==','',line).strip()

            data = set()

            # 穷尽所有可能
            for i in range(100000):
                data.add(expand_sentence(line))

            # 将每一句话都录制下来
            for line in data:
                if not task_config[scene_idx]['startPreReplyAudio']:
                    break

                if os.path.exists(os.path.join('config','回复音频',streamer,line)):
                    print(line,'这句话已预制，跳过')
                    continue

                print(line,'开始预制')

                refs = parse_ref_audio_text_by_streamer(streamer)

                if len(refs) > 1:
                    refs = random.sample(refs,1)

                # 每一个声音都生成一遍
                for ref in refs:
                    if not task_config[scene_idx]['startPreReplyAudio']:
                        break

                    response = requests.post('http://127.0.0.1:5000/generate_audio',data = {
                        'ref_file':ref['ref_wav'],
                        'ref_text':ref['ref_txt'],
                        'gen_text':line,
                        'speed': 1
                    })
                    
                    # 检查请求是否成功
                    if response.status_code == 200:
                        if not os.path.exists(os.path.join('config','回复音频',streamer)):
                            os.mkdir(os.path.join('config','回复音频',streamer))

                        if not os.path.exists(os.path.join('config','回复音频',streamer,line)):
                            os.mkdir(os.path.join('config','回复音频',streamer,line))

                        save_path = os.path.join('config','回复音频',streamer,line,'%s.wav' % datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))

                        with open(save_path, 'wb') as f4:
                            f4.write(response.content)


# 开始预制回复音频
@app.route('/startPreReplyAudio',methods = ['POST'])
def startPreReplyAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')
    product = request.form.get('product')
    streamer = request.form.get('streamer')

    task_config[scene_idx]['startPreReplyAudio'] = True

    task_thread = threading.Thread(target = startPreReplyAudioTask,args = (scene_idx,product,streamer))
    task_thread.start()

    return jsonify({'success':True})


# 暂停预制回复音频
@app.route('/stopPreReplyAudio',methods = ['POST'])
def stopPreReplyAudio():
    global task_config

    scene_idx = request.form.get('scene_idx')

    task_config[scene_idx]['startPreReplyAudio'] = False

    return jsonify({'success':True})


def init_struct():
    for prod in os.listdir(os.path.join('config','话术脚本')):
        if prod.startswith('.'):
            continue

        if prod == '通用':
            continue

        if not os.path.exists(os.path.join('config','话术音频',prod)):
            os.mkdir(os.path.join('config','话术音频',prod))

        if not os.path.exists(os.path.join('config','话术音频',prod,'主播')):
            os.mkdir(os.path.join('config','话术音频',prod,'主播'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'临时')):
            os.mkdir(os.path.join('config','话术音频',prod,'临时'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'主播','scene-1')):
            os.mkdir(os.path.join('config','话术音频',prod,'主播','scene-1'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'主播','scene-2')):
            os.mkdir(os.path.join('config','话术音频',prod,'主播','scene-2'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'主播','scene-3')):
            os.mkdir(os.path.join('config','话术音频',prod,'主播','scene-3'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'主播','scene-4')):
            os.mkdir(os.path.join('config','话术音频',prod,'主播','scene-4'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'主播','scene-5')):
            os.mkdir(os.path.join('config','话术音频',prod,'主播','scene-5'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'临时','scene-1')):
            os.mkdir(os.path.join('config','话术音频',prod,'临时','scene-1'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'临时','scene-2')):
            os.mkdir(os.path.join('config','话术音频',prod,'临时','scene-2'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'临时','scene-3')):
            os.mkdir(os.path.join('config','话术音频',prod,'临时','scene-3'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'临时','scene-4')):
            os.mkdir(os.path.join('config','话术音频',prod,'临时','scene-4'))

        if not os.path.exists(os.path.join('config','话术音频',prod,'临时','scene-5')):
            os.mkdir(os.path.join('config','话术音频',prod,'临时','scene-5'))

        if not os.path.exists(os.path.join('config','话术脚本',prod,'文本库')):
            os.mkdir(os.path.join('config','话术脚本',prod,'文本库'))

        if not os.path.exists(os.path.join('config','话术脚本',prod,'文本库','scene-1')):
            os.mkdir(os.path.join('config','话术脚本',prod,'文本库','scene-1'))

        if not os.path.exists(os.path.join('config','话术脚本',prod,'文本库','scene-2')):
            os.mkdir(os.path.join('config','话术脚本',prod,'文本库','scene-2'))

        if not os.path.exists(os.path.join('config','话术脚本',prod,'文本库','scene-3')):
            os.mkdir(os.path.join('config','话术脚本',prod,'文本库','scene-3'))

        if not os.path.exists(os.path.join('config','话术脚本',prod,'文本库','scene-4')):
            os.mkdir(os.path.join('config','话术脚本',prod,'文本库','scene-4'))

        if not os.path.exists(os.path.join('config','话术脚本',prod,'文本库','scene-5')):
            os.mkdir(os.path.join('config','话术脚本',prod,'文本库','scene-5'))


if __name__ == '__main__':
    init_struct()

    app.run(debug = True,port = 6868,host = '0.0.0.0')
